package main

import (
	"fmt"
	"sort"
)

func main() {
	//Go的切片
	//为什么要使用切片
	//切片（Slice）是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。 它非常灵活，支持自动扩容。
	//
	//切片是一个引用类型，它的内部结构包含地址、长度和容量。
	//声明切片类型的基本语法如下：
	//
	//var name [] T
	//其中：
	//
	//name：表示变量名
	//T：表示切片中的元素类型
	//举例

	// 声明切片，把长度去除就是切片
	var slice1 = []int{1, 2, 3}
	fmt.Println(slice1)

	//关于nil的认识
	//当你声明了一个变量，但却还并没有赋值时，golang中会自动给你的变量赋值一个默认的零值。这是每种类型对应的零值。
	//bool：false
	//numbers：0
	//string：""
	//pointers：nil
	//slices：nil
	//maps：nil
	//channels：nil
	//functions：nil
	//nil表示空，也就是切片(数组)初始化的默认值就是nil
	var slice2 []int
	fmt.Println(slice2 == nil)
	//fmt.Printf("%d", slice2)

	//切片的遍历
	//切片的遍历和数组是一样的
	slice3 := []int{1, 2, 3, 4, 5, 6}
	//	方式1
	for i := 0; i < len(slice3); i++ {
		fmt.Println(slice3[i])
	}
	fmt.Println("-------")
	//	方式2
	for _, v := range slice3 {
		fmt.Println(v)
	}

	//	基于数组定义切片
	//由于切片的底层就是一个数组，所以我们可以基于数组来定义切片
	//	切片可以通过数组的方式去定义 就直观的感觉 把一个现有的数组 切出一部分变成切片
	var array11 = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	fmt.Printf("类型为:%T,值为:%v\n", array11, array11)
	//	通过数组返回所有的值变成一个切片
	new_slice1 := array11[:]
	fmt.Printf("类型为:%T,值为:%v\n", new_slice1, new_slice1)
	//	按照数组的下标获取指定的切片 [num:num] 注意这里不包括最后下标值
	new_slice2 := array11[2:5]
	fmt.Printf("类型为:%T,值为:%v\n", new_slice2, new_slice2)
	//	获取数组下标之前的所有值变成切片 不包括最后的下标值
	new_slice3 := array11[:6]
	fmt.Printf("类型为:%T,值为:%v\n", new_slice3, new_slice3)
	//	从某个下标开始获取到最后 包括最开始的下标值
	new_slice4 := array11[5:]
	fmt.Printf("类型为:%T,值为:%v\n", new_slice4, new_slice4)
	//	注意  上述同理，我们不仅可以对数组进行切片，还可以切片在切片

	//切片的长度和容量
	//切片拥有自己的长度和容量，我们可以通过使用内置的len）函数求长度，使用内置的cap（） 函数求切片的容量。
	//切片的长度就是它所包含的元素个数。
	//切片的容量是从它的第一个元素开始数，到其底层数组元素末尾的个数。切片s的长度和容量可通过表达式len（s）和cap（s）来获取。
	//	实例
	slice4 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}
	fmt.Printf("切片的长度为%d，切片的容量为%d\n", len(slice4), cap(slice4))
	slice5 := slice4[2:5]
	fmt.Printf("新的切片值为%v,切片的长度为%d，切片的容量为%d\n", slice5, len(slice5), cap(slice5))
	slice6 := slice4[:6]
	//[1,2,3,4,5,6] 6 13
	fmt.Printf("新的切片值为%v,切片的长度为%d，切片的容量为%d\n", slice6, len(slice6), cap(slice6))
	slice7 := slice4[2:]
	//[3,4,5,6,7,8,9,10,11,12,13] 11 11
	fmt.Printf("新的切片值为%v,切片的长度为%d，切片的容量为%d\n", slice7, len(slice7), cap(slice7))
	//切片的本质
	//切片的本质就是对底层数组的封装，它包含了三个信息
	//
	//底层数组的指针
	//切片的长度(len)
	//切片的容量(cap)

	//使用make函数构造切片
	//我们上面都是基于数组来创建切片的，如果需要动态的创建一个切片，我们就需要使用内置的make函数，格式如下：
	//
	//make ([]T, size, cap)
	//其中：
	//
	//T：切片的元素类型
	//size：切片中元素的数量
	//cap：切片的容量
	//	例子
	slice8 := make([]int, 4, 8)
	fmt.Println(slice8)
	fmt.Printf("slice值为%v,切片的长度为%d，切片的容量为%d\n", slice8, len(slice8), cap(slice8))

	//需要注意的是，golang中没办法通过下标来给切片扩容，如果需要扩容，需要用到append
	slice9 := []int{1, 2, 3, 4}
	slice9 = append(slice9, 5, 6)
	fmt.Println(slice9)
	//同时切片还可以将两个切片进行合并
	slice10 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	slice9 = append(slice9, slice10...)
	fmt.Println(slice9)
	//	需要注意的是，切片会有一个扩容操作，当元素存放不下的时候，会将原来的容量扩大两倍

	//使用copy()函数复制切片
	//前面我们知道，切片就是引用数据类型
	//
	//值类型：改变变量副本的时候，不会改变变量本身
	//引用类型：改变变量副本值的时候，会改变变量本身的值
	//如果我们需要改变切片的值，同时又不想影响到原来的切片，那么就需要用到copy函数
	slice11 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	slice12 := make([]int, len(slice11), cap(slice11))
	copy(slice12, slice11)
	//slice12 = slice11
	fmt.Println(slice11, slice12)
	slice12[0] = 100
	fmt.Println(slice11, slice12)

	//删除切片中的值
	//Go语言中并没有删除切片元素的专用方法，我们可以利用切片本身的特性来删除元素。代码如下
	// 删除切片中的值
	var slices6 = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	// 删除下标为1的值
	slices6 = append(slices6[:1], slices6[2:]...)
	fmt.Println(slices6)

	//切片的排序算法以及sort包
	//编写一个简单的冒泡排序算法

	var numSlice = []int{9, 8, 7, 6, 5, 4}
	for i := 0; i < len(numSlice); i++ {
		flag := false
		for j := 0; j < len(numSlice)-i-1; j++ {
			if numSlice[j] > numSlice[j+1] {
				var temp = numSlice[j+1]
				numSlice[j+1] = numSlice[j]
				numSlice[j] = temp
				flag = true
			}
		}
		if !flag {
			break
		}
	}
	fmt.Println(numSlice)

	//对于int、float64 和 string数组或是切片的排序，go分别提供了
	//sort.Ints()、
	//sort.Float64s()
	//和 sort.Strings()函数，默认都是从小到大进行排序
	var numSlice2 = []int{9, 8, 7, 6, 5, 4}
	sort.Ints(numSlice2)
	fmt.Println(numSlice2)

	//降序排列
	//Golang的sort包可以使用 sort.Reverse(slic e) 来调换slice.Interface.Less，
	//也就是比较函数，所以int、float64 和 string的逆序排序函数可以这样写

	// 逆序排列
	var numSlice4 = []int{9, 8, 4, 5, 1, 7}
	sort.Sort(sort.Reverse(sort.IntSlice(numSlice4)))
	fmt.Println(numSlice4)

	var slice13 []int
	slice13 = append(slice13, 1)
	fmt.Println(slice13)
}
